package com.wlyuan.open.scanner.repository.impl;

import com.wlyuan.open.scanner.assembler.ScannerPayAssembler;
import com.wlyuan.open.scanner.constant.Constants;
import com.wlyuan.open.scanner.dao.entity.BalanceCheckDetailsDO;
import com.wlyuan.open.scanner.dao.entity.PayDO;
import com.wlyuan.open.scanner.dao.mapper.BalanceCheckDetailsMapper;
import com.wlyuan.open.scanner.dao.mapper.FinanceBillMapper;
import com.wlyuan.open.scanner.dao.mapper.PayMapper;
import com.wlyuan.open.scanner.dao.mapper.WaybillMapper;
import com.wlyuan.open.scanner.domain.finance.pay.BillPay;
import com.wlyuan.open.scanner.domain.finance.pay.BillPayConvert;
import com.wlyuan.open.scanner.domain.transport.Transport;
import com.wlyuan.open.scanner.repository.BillPayRepository;
import com.wlyuan.open.scanner.repository.PayRepository;
import com.wlyuan.open.scanner.utils.enums.bill.PayTypeEnum;
import com.wlyuan.open.utils.LongUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @author lijing
 * @description
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class BillPayRepositoryImpl implements BillPayRepository {
    private final BalanceCheckDetailsMapper balanceCheckDetailsMapper;
    private final PayMapper payMapper;
    private final BaseOrderRepository baseOrderRepository;
    private final PayRepository payRepository;
    private final BillTransportRepository billTransportRepository;
    private final TenantCheckRepository tenantCheckRepository;
    private final WaybillMapper waybillMapper;
    private final FinanceBillMapper financeBillMapper;
    private final PayBillCarrierCustomerRepository payBillCarrierCustomerRepository;

    @Override
    public void sync() {
        var count = payMapper.count();
        logger.info("收款单老数据数据量，size：{}", count);
        var pages = (int) Math.ceil(count * 1.0 / Constants.PAGE_SIZE);
        for (int i = 1; i <= pages; i++) {
            logger.info("开始同步收款单数据：第{}页，共{}页", i, pages);
            var list = payMapper.list(i, Constants.PAGE_SIZE);
            list.forEach(data -> {
                try {
                    var ts = parse(data);
                    var assemble = ScannerPayAssembler.assemble(ts);
                    baseOrderRepository.sync(assemble);
                } catch (Exception e) {
                    logger.error("同步收款单异常：{},{}", data.getId(), e);
                }
            });
        }
        logger.info("收付款同步完成......");
    }

    @Override
    public List<BillPay> list() {
        return Collections.emptyList();
    }

    @Override
    public BillPay getById(Long checkId) {
        return Optional.ofNullable(checkId).map(id -> {
            var finance = payRepository.getByUpOrDown(id);
            return Optional.ofNullable(finance).map(data -> parse(data)).orElse(null);
        }).orElse(null);
    }

    @Override
    public List<Long> getByTime(String startTime, String endTime) {
        return payRepository.getTime(startTime, endTime);
    }

    @Override
    public List<Long> getByTenantIdTime(Long tenantId, String startTime, String endTime) {
        return payRepository.getTenantIdTime(tenantId, startTime, endTime);
    }

    @Override
    public void getByTenantId(Long tenantId) {
        var count = payMapper.countByTenantId(tenantId);
        logger.info("租户{}收款单老数据数据量，size：{}", tenantId, count);
        var pages = (int) Math.ceil(count * 1.0 / Constants.PAGE_SIZE);
        for (int i = 1; i <= pages; i++) {
            logger.info("开始同步租户{}收款单数据：第{}页，共{}页", tenantId, i, pages);
            var list = payMapper.listByTenantId(i, Constants.PAGE_SIZE, tenantId);
            list.forEach(data -> {
                try {
                    var ts = parse(data);
                    baseOrderRepository.sync(ScannerPayAssembler.assemble(ts));
                } catch (Exception e) {
                    logger.error("收款单同步异常：{},{}", data.getId(), e);
                }
            });
        }
        logger.info("租户{}收款单同步完成......", tenantId);
    }


    @Override
    public BillPay parse(PayDO pay) {
        if (tenantCheckRepository.checkTenant(pay.getTenantId())) {
            logger.error("收付款id：{},{},租户id:{}", pay.getUp(), pay.getDown(), pay.getTenantId());
            return null;
        }
        //是否回执付
        if (PayTypeEnum.isReturnPay(pay.getType())) {
            return getReturnPay(pay.getId(), pay.getUp(), pay.getDown());
        }
        //预付，到付，代收
        return getNoReturnPay(pay.getId(), pay.getUp(), pay.getDown());
    }

    private BillPay getReturnPay(Long id, Long up, Long down) {
        if (LongUtils.notNullLong(up) && LongUtils.notNullLong(down)) {
            var data = balanceCheckDetailsMapper.getReturnPayById(up);
            process(data, id);
            var billPay = BillPayConvert.convert(data, down);
            billPay.setWaybills(payBillCarrierCustomerRepository.processWayBill(data.getRecId()));
            billUpStream(data, data.getRecId());
            billPay.setUpStream(BillPayConvert.upConvert(data));
            //下游
            var downData = balanceCheckDetailsMapper.getReturnPayById(down);
            process(downData, id);
            billDownStream(downData, downData.getRecId());
            billPay.setDownStream(BillPayConvert.downConvert(downData));
            return billPay;
        }
        //线下客户 up = null , down != null  / 线下承运方 up != null , down = null
        var data = LongUtils.notNullLong(up) ? balanceCheckDetailsMapper.getReturnPayById(up) : balanceCheckDetailsMapper.getReturnPayById(down);
        process(data, id);
        var billPay = BillPayConvert.convert(data, down);
        //billPay.setWaybills(billRepository.processWayBill(data.getRecId()));

        billUpStream(data, data.getRecId());
        billDownStream(data, data.getRecId());

        billPay.setDownStream(BillPayConvert.downConvert(data));
        billPay.setUpStream(BillPayConvert.upConvert(data));
        if (!LongUtils.notNullLong(down)) {
            billPay.getDownStream().setCollect(null);
        }
        if (!LongUtils.notNullLong(up)) {
            billPay.getUpStream().setPayment(null);
        }
        //回执付
        if (data.getRecId() != null) {
            billPay.setWaybills(payBillCarrierCustomerRepository.processWayBill(data.getRecId()));
        } else {
            var transport = billTransportRepository.getBillByTransportId(data.getCheckDetailorderid());
            if (transport != null) {
                List<Transport> list = new ArrayList<>();
                list.add(transport);
                billPay.setWaybills(list);
            }
        }
        return billPay;
    }

    private void billUpStream(BalanceCheckDetailsDO data, Long billId) {
        var bill = payBillCarrierCustomerRepository.getById(billId);
        if (bill == null) {
            logger.error("收付款upStream未找到对应的对账单：{},{}", data.getCheckDetailid(), billId);
            return;
        }
        data.setUpTenantId(bill.getUpStream().getTenantId());
        data.setCarrierType(bill.getUpStream().getCarrierType());
    }

    private void billDownStream(BalanceCheckDetailsDO data, Long billId) {
        var bill = payBillCarrierCustomerRepository.getById(billId);
        if (bill == null) {
            logger.error("收付款downStream未找到对应的对账单：{},{}", data.getCheckDetailid(), billId);
            return;
        }
        data.setDownTenantId(bill.getDownStream().getTenantId());
        data.setCustomerType(bill.getDownStream().getCustomerType());
    }

    private BillPay getNoReturnPay(Long id, Long up, Long down) {
        if (LongUtils.notNullLong(up) && LongUtils.notNullLong(down)) {
            var data = balanceCheckDetailsMapper.getNoReturnPayById(up);
            process(data, id);
            var billPay = BillPayConvert.convert(data, down);
            transportUpStream(data, billPay);
            billPay.setUpStream(BillPayConvert.upConvert(data));
            //下游
            var downData = balanceCheckDetailsMapper.getNoReturnPayById(down);
            process(downData, id);
            transportDownStream(downData, downData.getCheckDetailorderid());
            billPay.setDownStream(BillPayConvert.downConvert(downData));
            return billPay;
        }
        var data = LongUtils.notNullLong(up) ? balanceCheckDetailsMapper.getNoReturnPayById(up) : balanceCheckDetailsMapper.getNoReturnPayById(down);
        process(data, id);
        var billPay = BillPayConvert.convert(data, down);

        transportUpStream(data, billPay);
        transportDownStream(data, data.getCheckDetailorderid());

        billPay.setDownStream(BillPayConvert.downConvert(data));
        billPay.setUpStream(BillPayConvert.upConvert(data));
        //设置收付款信息
        if (!LongUtils.notNullLong(down)) {
            billPay.getDownStream().setCollect(null);
        }
        if (!LongUtils.notNullLong(up)) {
            billPay.getUpStream().setPayment(null);
        }
        //回执付
        if (data.getRecId() != null) {
            billPay.setWaybills(payBillCarrierCustomerRepository.processWayBill(data.getRecId()));
        }
        return billPay;
    }

    private void transportUpStream(BalanceCheckDetailsDO data, BillPay billPay) {
        var transport = billTransportRepository.getBillByTransportId(data.getCheckDetailorderid());
        if (Optional.ofNullable(transport).isPresent()) {
            if (Optional.ofNullable(transport.getCarrier()).isPresent()) {
                data.setCarrierType(transport.getCarrier().getCarrierType());
                data.setUpTenantId(transport.getCarrier().getTenantId());
            }

            List<Transport> list = new ArrayList<>();
            list.add(transport);
            billPay.setWaybills(list);
        }
    }

    private void transportDownStream(BalanceCheckDetailsDO data, Long transportId) {
        var transport = billTransportRepository.getBillByTransportId(transportId);
        if (Optional.ofNullable(transport).isPresent() && Optional.ofNullable(transport.getCustomer()).isPresent()) {
            data.setCustomerType(transport.getCustomer().getCustomerType());
            data.setDownTenantId(transport.getCustomer().getTenantId());
            /*if (transport.getCustomer().getFinanceStatus() != null) {
                data.setFinanceStatus(transport.getCustomer().getFinanceStatus().getValue());
            }*/
        }
    }

    private void process(BalanceCheckDetailsDO data, Long payId) {
        data.setPayId(payId);

        //收付款对应的运单id， 有可能是舍弃的下游的客户端id，需要修改成上游的运单id
        if (data.getCheckDetailorderid() != null) {
            Optional.ofNullable(waybillMapper.getByUpOrDown(data.getCheckDetailorderid())).ifPresent(t -> {
                data.setCheckDetailorderid(t.getUp());
            });
        }

        if (data.getCheckDetailownerid() != null) {
            Optional.ofNullable(financeBillMapper.getByUpOrDown(data.getCheckDetailownerid())).ifPresent(f -> {
                if (LongUtils.notNullLong(f.getUp())) {
                    data.setCheckDetailownerid(f.getUp());
                }
            });
        }
    }
}
